# coding=utf-8
import sys,os
import random
import pygame
from pygame import math
from pygame.locals import *
from math import *


# 用到的图片和音乐相对路径
background_image_filename = os.path.join('resources','1.png')
grass_image_filename = os.path.join('resources','grass.png')
head1_image_filename = os.path.join('resources','snake_head1.png')
head2_image_filename = os.path.join('resources','snake_head2.png')
body1_image_filename = os.path.join('resources','snake_body1.png')
body2_image_filename = os.path.join('resources','snake_body2.png')
food_image_filename = os.path.join('resources','food.png')
shit_image_filename = os.path.join('resources','shit.png')
player_image_filename = os.path.join('resources','play.png')
gameover1_image_filename = os.path.join('resources','gameover1.png')
gameover2_image_filename = os.path.join('resources','gameover2.png')
background_music_filename = os.path.join('resources','The_Happy_Dance.mp3')
cat_music_filename = os.path.join('resources','cat.wav')
catshit_music_filename = os.path.join('resources','cat_shit.wav')

pygame.init()
# 设置窗口位置
os.environ['SDL_VIDEO_WINDOW_POS'] = "{0},{1}".format(50,70)
# 设置窗口大小
width,height = 640,480
screen = pygame.display.set_mode((width, height), 0, 32)
pygame.display.set_caption('玩蛇大战')
clock = pygame.time.Clock()
# 加载背景图片
background = pygame.image.load(background_image_filename).convert()
playeroper = pygame.image.load(player_image_filename).convert()
# 加载结束图片
over1 = pygame.image.load(gameover1_image_filename).convert_alpha()
over2 = pygame.image.load(gameover2_image_filename).convert_alpha()
# 前景图片
foreground = pygame.image.load(grass_image_filename).convert_alpha()
# 重复播放背景音乐
pygame.mixer.music.load(background_music_filename)
pygame.mixer.music.play(-1)


class Snake():
    '''
    蛇类，用于控制蛇的移动和碰撞检测以及输赢状态
    '''
    
    def __init__(self, head_image, pos,speed,body_image):
        '''
        head_image:头部图片路径
        pos:头部初始位置
        speed:每秒前进的速度
        body_image:身体图片路径
        '''
        self.head = pygame.image.load(head_image).convert_alpha()
        self.pos = pos
        self.speed = speed
        self.body_image = pygame.image.load(body_image).convert_alpha()
        self.rotation = 0
        self.path = []  # 头部走过的路径(坐标)
        self.x=0  # 当前头部的x坐标
        self.y=0  # 当前头部的y坐标
        self.is_dead = False  # 死亡状态判断
        self.is_win = False  # 输赢状态判断
        self.length = 4  # 初始身体长度
        self.body = []  # 所有身体的坐标

    
    def update(self,time_passed_seconds):
        '''
        更新位置
        time_passed_seconds:间隔时间(秒)
        '''
        if self.is_dead or self.is_win:
            return
        # 计算前进方向
        x = sin(self.rotation*pi/180)
        y = cos(self.rotation*pi/180)
        # 转换为单位速度向量
        heading = math.Vector2(x, y)
        self.pos += -heading * self.speed * time_passed_seconds
        # 穿墙
        if self.pos.x > width:
            self.pos.x = 0
        if self.pos.x < 0:
            self.pos.x = width
        if self.pos.y > height:
            self.pos.y = 0
        if self.pos.y < 0:
            self.pos.y = height
        # 获取旋转后的蛇头
        rotated_sprite = pygame.transform.rotate(self.head, self.rotation)
        # 获得长宽
        self.w, self.h = rotated_sprite.get_size()
        # 绘制蛇的坐标
        self.x = self.pos.x - self.w/2
        self.y = self.pos.y - self.h/2
        sprite_draw_pos = math.Vector2(self.x, self.y)
        screen.blit(rotated_sprite, sprite_draw_pos)
        # 添加移动路径
        pos=(self.x,self.y)
        self.path.append(pos)
        # 刷新身体
        self.body=[]
        sp=int(round(25000.0 / self.speed))
        for i in range(self.length):
            index = (i + 1) * sp + 1
            location = self.path[-min(index,len(self.path))]
            screen.blit(self.body_image, location)
            self.body.append(location)
        le = max(self.length * 200 * 2, 60)
        if len(self.path) > le:
            self.path = self.path[int(-le * 2):]
        # 检测输赢
        self.is_wins()
        self.is_lost()

    def rotation_angle_p1(self,keys):
        '''
        玩家1头部的旋转角度
        keys:按下的键
        '''
        if self.is_dead or self.is_win:
            return
        # 根据按键确定x和y的值
        x, y = 0, 0
        if keys[K_LEFT]:
            y = +1
        if keys[K_RIGHT]:
            y = -1
        if keys[K_UP]:
            x = +1
        if keys[K_DOWN]:
            x = -1
        # 定义角度导向元祖，根据xy的值确定旋转角度
        directs = ((225, 180, 135), (270, None, 90), (315, 0, 45))
        direct = directs[x + 1][y + 1]
        # 如果没有按下的键就还是原来的角度，否则更新角度
        if direct is None:
            self.rotation = self.rotation
        else:
            self.rotation = direct

    def rotation_angle_p2(self,keys):
        '''
        玩家2头部的旋转角度
        keys:按下的键
        '''
        if self.is_dead or self.is_win:
            return
        # 根据按键确定x和y的值
        x, y = 0, 0
        if keys[ord('a')]:
            y = +1
        if keys[ord('d')]:
            y = -1
        if keys[ord('w')]:
            x = +1
        if keys[ord('s')]:
            x = -1
        # 定义角度导向元祖，根据xy的值确定旋转角度
        directs = ((225, 180, 135), (270, None, 90), (315, 0, 45))
        direct = directs[x + 1][y + 1]
        # 如果没有按下的键就还是原来的角度，否则更新角度
        if direct is None:
            self.rotation = self.rotation
        else:
            self.rotation = direct

    def eat_food(self,pos,is_shit):
        '''
        食物碰撞检测
        pos:食物位置
        is_shit:是否是屎
        '''
        if self.is_dead or self.is_win:
            return
        # 根据食物位置和蛇头位置检测是否碰撞
        if abs(self.x-pos[0]) < self.w/1.5 and abs(self.y-pos[1]) < self.h/1.5:
            if is_shit:
                # 如果是屎，播放吃屎音效
                pygame.mixer.Sound(catshit_music_filename).play()
                # 每次吃屎减速12，速度有封顶
                if self.speed > 50:
                    self.speed -= 12
            else:
                # 如果是食物，播放吃食物音效
                pygame.mixer.Sound(cat_music_filename).play()
                # 每次吃食物长度加1，速度减6，速度有封顶
                self.length = self.length + 1
                if self.speed > 50:
                    self.speed -= 6
            return True
        return False

    def is_wins(self):
        '''
        判断玩家是否胜利，如果长度大于一定值则胜利
        '''
        if self.length > 22:
            self.is_win  = True
        else:
            self.is_win = False

    def is_lost(self):
        '''
        判断玩家是否死亡，如果长度小于等于0则胜利
        '''
        if self.length <= 0:
            self.is_dead  = True
        else:
            self.is_dead = False


class Food():
    '''
    食物类，用于生成和刷新食物位置
    '''

    def __init__(self,food_image):
        '''
        food_image:食物图片路径
        '''
        self.food_image = pygame.image.load(food_image).convert_alpha()  # 加载食物图片
        self.mini_food=pygame.transform.scale(self.food_image, (300, 300))  # 缩小食物图片
        # 每个食物的位置
        self.foods=[(30, 25, 45, 45),
                    (80, 25, 45, 45),
                    (130, 25, 45, 45),
                    (180, 25, 45, 45),
                    (230, 25, 45, 45)
                    ]
        self.w = 45  # 食物宽度
        self.h = 45  # 食物高度
        self.is_eaten = False  # 食物是否被吃
        self.x = random.randint(self.w ,width-self.w)  # 食物刷新x坐标
        self.y = random.randint(self.h ,height-self.h)  # 食物刷新y坐标
        self.index = random.randint(0,4)  # 食物种类

    def reset(self):
        '''
        被吃掉时刷新食物位置
        '''
        if self.is_eaten:
            self.x = random.randint(self.w ,width-self.w)
            self.y = random.randint(self.h ,height-self.h)
            self.eat = False
            self.index = random.randint(0,4)
    
    def bulid_mini(self):
        '''
        绘制不同种类的食物
        '''
        screen.blit(self.mini_food, (self.x,self.y),self.foods[self.index])
    
    def bulid_img(self):
        '''
        直接通过图片绘制食物
        '''
        screen.blit(self.food_image, (self.x,self.y))


def main():
    # 初始化两个玩家
    snake_P1=Snake(head1_image_filename,math.Vector2(200, 150),200,body1_image_filename)
    snake_P2=Snake(head2_image_filename,math.Vector2(400, 150),200,body2_image_filename)
    # 初始化食物和屎
    food=Food(food_image_filename)
    food2=Food(food_image_filename)
    food_shit=Food(shit_image_filename)
    # 开始和结束的状态
    end = False
    sat = False
    # 获取字体
    cur_font = pygame.font.SysFont("SimHei", 32)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if event.type == pygame.KEYDOWN:
                sat = True
                # 游戏结束时按空格键再玩一次
                if event.key == pygame.K_SPACE and end:
                    return main()

        screen.blit(background, (0,0))
        # 如果游戏没开始则显示开始画面
        if not sat:
            screen.blit(playeroper, (100,50))
            pygame.display.update()
            continue
        # 间隔时间(秒)
        time_passed_sec=clock.tick()/1000.0
        if not end:
            # 玩家p1操作
            snake_P1.rotation_angle_p1(pygame.key.get_pressed())
            snake_P1.update(time_passed_sec)
            # 玩家p2操作
            snake_P2.rotation_angle_p2(pygame.key.get_pressed())
            snake_P2.update(time_passed_sec)
        # 吃食物判断
        if snake_P1.eat_food((food.x,food.y),False):
            food.is_eaten=True
            food.reset()
        if snake_P2.eat_food((food.x,food.y),False):
            food.is_eaten=True
            food.reset()
        if snake_P1.eat_food((food2.x,food2.y),False):
            food2.is_eaten=True
            food2.reset()
        if snake_P2.eat_food((food2.x,food2.y),False):
            food2.is_eaten=True
            food2.reset()
        # 吃屎让对手掉一节长度
        if snake_P1.eat_food((food_shit.x,food_shit.y),True):
            snake_P2.length -= 1
            food_shit.is_eaten=True
            food_shit.reset()
        if snake_P2.eat_food((food_shit.x,food_shit.y),True):
            snake_P1.length -= 1
            food_shit.is_eaten=True
            food_shit.reset()
        # 生成食物
        food.bulid_mini()
        food2.bulid_mini()
        food_shit.bulid_img()
        # 如果有玩家赢，显示结束画面
        if snake_P1.is_win or snake_P2.is_dead:
            screen.blit(over1, (100,25))
            end=True
        if snake_P2.is_win or snake_P1.is_dead:
            screen.blit(over2, (100,25))
            end=True
        # 显示得分文字
        screen.blit(cur_font.render("玩家1长度:{0}".format(snake_P1.length+1), 1, (127,127,127)), (0,0))
        screen.blit(cur_font.render("玩家2长度:{0}".format(snake_P2.length+1), 1, (127,127,127)), (400,0))
        screen.blit(cur_font.render("目标长度:{0}".format(24), 1, (127,127,127)), (400,400))
        # 前景（太卡了，取消）
        #screen.blit(foreground, (0,0))
        # 刷新屏幕
        pygame.display.update()

if __name__ == '__main__':
    main()